﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GKS.DataTypes.Math {
    public struct ComplexNumber : INumber {
        #region variables
        private double real;// = 0;
        private double imaginary;// = 0;
        #endregion

        #region properties
        public double Real {
            get { return real; }
            set { real = value; }
        }
        public double Imaginary {
            get { return imaginary; }
            set { imaginary = value; }
        }

        public ComplexNumber Conjugate {
            get { return new ComplexNumber(Real, Imaginary * (-1)); }
        }
        public ComplexNumber Sqrt {
            get {
                return new ComplexNumber(
                    System.Math.Sqrt(Real + System.Math.Sqrt((Real * Real) + (Imaginary * Imaginary)) / 2),
                    System.Math.Sqrt(-Real + System.Math.Sqrt((Real * Real) + (Imaginary * Imaginary)) / 2) * ((Imaginary < 0) ? -1 : 1));
            }
        }
        #endregion

        #region enums

        #endregion

        #region constructors
        ///// <summary>
        ///// A constructor of a complex number instance.
        ///// </summary>
        //public Complex() : this(0, 0) { }

        public ComplexNumber(double real) : this(real, 0) { }

        /// <summary>
        /// A constructor of a Complex number instance.
        /// </summary>
        /// <param name="real">The real part of the complex number.</param>
        /// <param name="imaginary">The imaginary part of the complex number.</param>
        public ComplexNumber(double real, double imaginary) {
            this.real = real;
            this.imaginary = imaginary;
        }
        #endregion

        #region methods
        /// <summary>
        /// A method that returns a string representation of this Complex number.
        /// </summary>
        /// <returns>
        /// A string representation of this Complex number.
        /// </returns>
        public override string ToString() {
            return string.Format("{0} + {1}i", Real, Imaginary);
        }

        public override bool Equals(object obj) {
            return (obj is ComplexNumber) ? Equals((ComplexNumber)obj) : false;
        }

        public override int GetHashCode() {
            return (Real.GetHashCode() ^ Imaginary.GetHashCode());
        }

        public bool Equals(ComplexNumber another) {
            return this == another;
        }
        #endregion

        #region operators
        #region mathematical operations
        /// <summary>
        /// The addition operator.
        /// </summary>
        /// <param name="first">The first number needed for an addition.</param>
        /// <param name="second">The second number needed for an addition.</param>
        /// <returns>The result of the sum between two Complex numbers.</returns>
        public static ComplexNumber operator +(ComplexNumber first, ComplexNumber second) {
            return new ComplexNumber(first.Real + second.Real, first.Imaginary + second.Imaginary);
        }

        public static ComplexNumber operator -(ComplexNumber first, ComplexNumber second) {
            return new ComplexNumber(first.Real - second.Real, first.Imaginary - second.Imaginary);
        }

        public static ComplexNumber operator *(ComplexNumber first, ComplexNumber second) {
            return new ComplexNumber(
                (first.Real * second.Real) - (first.Imaginary * second.Imaginary),
                (first.Real * second.Imaginary) + (first.Imaginary + second.Real));
        }

        public static ComplexNumber operator /(ComplexNumber numerator, ComplexNumber denominator) {
            double real = ((numerator.Real * denominator.Real) + (numerator.Imaginary * denominator.Imaginary)) 
                    / ((denominator.Real * denominator.Real) + (denominator.Imaginary * denominator.Imaginary));
            double imaginary = ((numerator.Imaginary * denominator.Real) - (numerator.Real * denominator.Imaginary))
                    / ((denominator.Real * denominator.Real) + (denominator.Imaginary * denominator.Imaginary));
            return new ComplexNumber(real, imaginary);
        }
        #endregion

        #region boolean operations
        public static bool operator ==(ComplexNumber first, ComplexNumber second) {
            return first.Real == second.Real && first.Imaginary == second.Imaginary;
        }

        public static bool operator !=(ComplexNumber first, ComplexNumber second) {
            return !(first == second);
        }
        #endregion

        #region cast operators
        public static explicit operator ComplexNumber (double value){
            return new ComplexNumber(value);
        }

        public static explicit operator double(ComplexNumber value) {
            return value.Real;
        }
        #endregion
        #endregion
    }
}
